

#include "server.h"
#include "channel.h"
#include "connection.h"
#include "define.h"
#include "loop_event.hpp"
#include <cstddef>
#include <iostream>
#include <cstring>
#include <functional>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <unistd.h>

#include <cassert>
Server::Server(LoopEvent * loop)
{
    m_loop = loop;
}

void Server::Listen(int port)
{
    struct sockaddr_in sai{};
    memset(&sai, 0, sizeof(sai));

    sai.sin_port = htons(port);
    sai.sin_addr.s_addr = INADDR_ANY;
    sai.sin_family = AF_INET;

    m_socket.Open();

    m_socket.SetOpt();
    m_socket.SetNonBlocking();

    assert(bind(m_socket.GetSocketFd(), (struct sockaddr*)&sai, sizeof(sai)) == 0);
    listen(m_socket.GetSocketFd(), 1024);

    Channel * channel = nullptr;
    channel = new Channel(m_loop, m_socket.GetSocketFd(),
                                   nullptr, std::bind(&Server::ReadCallback, this, std::placeholders::_1), nullptr);

    m_listen_channel = std::shared_ptr<Channel>(channel);
    m_listen_channel->AddEvent(EPOLLIN | EPOLLOUT | EPOLLERR);
}

void Server::ReadCallback(int64_t channel_id)
{
    int new_socket = accept(m_socket.GetSocketFd(), NULL, NULL);
    std::cout << "new socket fd : " << new_socket << std::endl;
    auto * connection = new Connection(m_loop, new_socket,
                                             std::bind(&Server::WriteCallback, this),
                                             std::bind(&Server::ProcessRead, this, std::placeholders::_1),
                                             std::bind(&Server::ErrorCallback, this, std::placeholders::_1, std::placeholders::_2));
    m_loop->PushTask([this, connection](){

        connection->RegisterChannel(EPOLLIN | EPOLLONESHOT | EPOLLET | EPOLLERR | EPOLLRDHUP);
        m_loop->PushTask([this, connection](){

            m_connection_map[connection->ChannelId()] = connection;
            if (m_connection_func)
            {
                m_connection_func(connection);
            }
        });
    });
}

void Server::SetOnConnectionFunc(ServerOnConnectFunc &&func)
{
    m_connection_func = func;
}

void Server::SetOnMessageFunc(ServerOnMessageFunc &&func)
{
    m_message_func = func;
}

void Server::SetOnDisconnectionFunc(ServerOnDisconnectFunc &&func)
{
    m_disconnection_func = func;
}

void Server::ProcessRead(int64_t channel_id)
{
    auto iter = m_connection_map.find(channel_id);
    if (iter != m_connection_map.end() && iter->second)
    {
        Connection * connection = iter->second;
        int status = 0;
        int read_size = connection->m_data_buffer->ReadData(status);
        if (status < 0)
        {
            ErrorCallback(connection->ChannelId(), 0);
        }
        else 
        {
            // todo call on message function
            if (m_message_func)
            {
                m_message_func(connection, connection->m_data_buffer->Data(), connection->m_data_buffer->Length());
            }
            else
            {
                connection->m_data_buffer->RemoveData(read_size);
            }
            if (connection->m_connection_channel)
            {
                connection->m_connection_channel->UpdateEvent(EPOLLIN | EPOLLONESHOT | EPOLLERR | EPOLLRDHUP);
            } 
        }
    }
}

void Server::WriteCallback()
{

}

void Server::ErrorCallback(int64_t channel_id, int error_code)
{
    if (channel_id == m_listen_channel->GetChannelId())
    {

    }
    else
    {
        auto iter = m_connection_map.find(channel_id);
        if (iter != m_connection_map.end() && iter->second)
        {
            std::cout << "remove channel id : " << channel_id << std::endl;
            if (iter->second->m_connection_channel)
            {
                iter->second->m_connection_channel->RemoveEvent();
            }
            delete iter->second;
            m_connection_map.erase(iter);
        }
    }
}
